import java.util.Scanner;

/**
 * This program prints out the day of the week for a given day, month and year.
 *
 * @author Sergii Koziumynskyi
 * @version 0.01 2014-01-16
 */

public class CalendarSeeker {
    enum Months {NULL, JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER }

    public static void main(String[] args) {

        // ask user about input
        Scanner in = new Scanner(System.in);
        System.out.println("Enter a date in 'DD Month YYYY' format. e.g. '10 October 2010'");
        String dirtyInput = in.nextLine().trim().toUpperCase();
        in.close();

        // convert the input to expected format
        String[] intermediateInput = dirtyInput.split(" ");
        int year = 0;   // 0 will show that something wrong with the input
        int month = 0;  // 0 will show that something wrong with the input
        int day = 0;    // 0 will show that something wrong with the input
        boolean invalidInput = false;
        if (intermediateInput.length != 3) {
            invalidInput = true;
            System.out.println("Invalid format of entered string.");
        } else {
            year = getYear(intermediateInput[2]);
            month = getMonth(intermediateInput[1]);
            day = getDay(intermediateInput[0], year, month);
        }

        // main calculations
        if (!invalidInput && year != 0 && month != 0 && day != 0) {
            int dayOfWeek = getDayOfWeek(year, month, day);
            String[] output = {"Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};
            System.out.println("Its " + output[dayOfWeek]);
        }
    }

    /**
     * Method tries to convert a received string to an integer representation of a year.
     *
     * @param intermediateInput string representation of year
     * @return
     *          zero (0) if intermediateInput cannot be converted to an integer
     *          integer representation of a year
     */
    private static int getYear(String intermediateInput) {
        int result = 0;
        try {
            result = Integer.parseInt(intermediateInput);
        } catch (NumberFormatException nfe) {
            System.out.println("Entered '" + intermediateInput + "' is not valid value for a year.");
        }
        return result;
    }

    /**
     * Method tries to convert a received string to an integer representation of a month.
     *
     * @param intermediateInput string representation of month (JUNE, JANUARY, etc.)
     * @return
     *          zero (0) if intermediateInput is not string representation of a month
     *          integer representation of a month (ex. 1 for JANUARY, 12 for DECEMBER)
     */
    private static int getMonth(String intermediateInput) {
        int result = 0;
        try {
            result = Months.valueOf(intermediateInput).ordinal();
        } catch (IllegalArgumentException iae) {
            System.out.println("Entered '" + intermediateInput + "' is not valid value for a month.");
        }
        return result;
    }

    /**
     * Method tries to convert a received string to an integer representation of a day of a month
     * and checks that the converted integer is a valid day of a month.
     *
     * @param intermediateInput string representation of day of month
     * @param year an integer with year; it is used for check 'is the day a valid day of February month'
     * @param month an integer in 0-12 diapason (0-Invalid Month mark, 1-January, 12-December);
     *              it represents month of the year and used for check 'is the day a valid day of month'
     * @return
     *          zero (0) if intermediateInput cannot be converted to an integer or if it is invalid day of month
     *          integer with valid day of month
     */
    private static int getDay(String intermediateInput, int year, int month) {
        int result = 0;
        try {
            result = Integer.parseInt(intermediateInput);

            // check the converted day is valid for the entered month
            if (month != 0) {
                int maxDay = 0;
                switch (month) {
                    case 1: case 3: case 5:
                    case 7: case 8: case 10:
                    case 12:
                        maxDay = 31;
                        break;
                    case 4: case 6:
                    case 9: case 11:
                        maxDay = 30;
                        break;
                    case 2:
                        if (((year % 400 == 0) &&
                                !(year % 100 == 0))
                                || (year % 4 == 0))
                            maxDay = 29;
                        else
                            maxDay = 28;
                        break;
                    default:
                        System.out.println("Something really wrong happen :)");
                        break;
                }
                if (result < 1 || result > maxDay) {
                    System.out.println("Entered day is not valid for the entered month.");
                    result = 0;
                }
            } // else
        } catch (NumberFormatException nfe) {
            System.out.println("Entered '" + intermediateInput + "' is not valid value for a day.");
        }

        return result;
    }

    /**
     * Method uses Zeller's congruence to calculate day of week for specified date
     * details: http://en.wikipedia.org/wiki/Zeller%27s_congruence
     *
     * @param year int with year;
     * @param month int with month
     * @param day int with month
     * @return int from 0 to 6 (0 = Saturday, 1 = Sunday, 2 = Monday, ...)
     */
    private static int getDayOfWeek(int year, int month, int day) {
        if (month < 3) {
            month += 12;
            year -= 1;
        } // else

        int k = year % 100; // year in the century
        int j = year / 100; // century
        return ((day + (((month + 1) * 26) / 10) + k + (k / 4) + (j / 4)) + (5 * j)) % 7;
    }
}
